package com.qzxy.premiumhotelsystem.controller.employee;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.annotation.SaMode;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import com.qzxy.premiumhotelsystem.common.annotation.LogExecutionTime;
import com.qzxy.premiumhotelsystem.common.constant.CaptchaConstant;
import com.qzxy.premiumhotelsystem.common.constant.UserRoleConstant;
import com.qzxy.premiumhotelsystem.common.enums.LogLevel;
import com.qzxy.premiumhotelsystem.common.exception.SqlException;
import com.qzxy.premiumhotelsystem.domain.entity.Employees;
import com.qzxy.premiumhotelsystem.domain.entity.Guests;
import com.qzxy.premiumhotelsystem.domain.vo.EmployeeInfoVo;
import com.qzxy.premiumhotelsystem.domain.vo.LoginVo;
import com.qzxy.premiumhotelsystem.domain.vo.UpdatePasswordVo;
import com.qzxy.premiumhotelsystem.common.result.Result;
import com.qzxy.premiumhotelsystem.service.EmployeesService;
import com.qzxy.premiumhotelsystem.service.LogsService;
import com.qzxy.premiumhotelsystem.utils.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

import static cn.dev33.satoken.SaManager.log;
import static com.qzxy.premiumhotelsystem.common.result.ResultCodeEnum.*;

/**
 * @Author: iQNRen
 * @Description: 员工接口
 * @Date: 2024/9/18 16:14 周三
 * @Version: 1.0
 */
@RestController
//@SaCheckRole(value = {UserRoleConstant.EMPLOYEE, UserRoleConstant.ADMIN}, mode = SaMode.OR)
@Tag(name = "员工接口")
@RequestMapping("/employees")
public class EmployeesController {
    @Resource
    private EmployeesService employeesService;
    @Resource
    private AliOSSUtils aliOSSUtils;
    @Resource
    private Bcrypt bcrypt;
    @Resource
    private LogsService logsService;

    @Operation(summary = "添加员工",description = "管理员权限")
//    @SaCheckRole(type = UserRoleConstant.ADMIN)
    @PostMapping("/create")
    public Result createEmployees(@RequestBody @Valid Employees employees) {
        employees.setPassword(bcrypt.encode("123456"));
        employees.setStatus("1");
        try {
            if (employeesService.save(employees)) {
//                logsService.create("创建员工" + employees.getTelephone());
                return Result.ok("创建员工成功");
            } else {
//                logsService.create("创建员工" + employees.getTelephone() + "失败");
                return Result.error("创建员工失败");
            }
        } catch (SqlException e) {
            throw new SqlException("插入失败，违反唯一约束或主键冲突。");
        }

    }

    @Operation(summary = "删除员工",description = "管理员权限")
//    @SaCheckRole(type = UserRoleConstant.ADMIN)
    @DeleteMapping("/delete/{telephone}")
    @LogExecutionTime(message = "删除员工",level = LogLevel.ERROR)
    public Result deleteEmployees(@PathVariable String telephone) {
        boolean b = employeesService.deleteByTelephoneBoolean(telephone);
        if (b != false) {
//            logsService.create("删除员工" + telephone);
            return Result.ok("员工删除成功");
        } else {
//            logsService.create("删除员工" + telephone + "失败");
            return Result.error("员工删除失败");
        }
    }

    @Operation(summary = "修改员工状态",description = "管理员权限")
    @SaCheckRole(type = UserRoleConstant.ADMIN)
    @LogExecutionTime(message = "修改员工状态",level = LogLevel.WARN)
    @PatchMapping("/status")
    public Result updateStateEmployees(@RequestParam @NotBlank String telephone,@RequestParam @NotBlank String status) {
        try {
            boolean b = employeesService.updateStatue(telephone,status);
            if (b != false) {
//                logsService.create("修改员工状态" + telephone);
                return Result.ok("修改员工状态成功");
            } else {
//                logsService.create("修改员工状态" + telephone + "失败");
                return Result.error("修改员工状态失败");
            }
        } catch (SqlException e) {
            throw new SqlException("插入失败，违反唯一约束或主键冲突。");
        }
    }


    // 员工自己的权限

    @Operation(summary = "员工查询(电话)")
    @GetMapping("/tel/{telephone}")
    public Result searchTel(@PathVariable @NotBlank String telephone) {
        return Result.ok(employeesService.getByTelephone(telephone));
    }

    @Operation(summary = "员工分页查询")
    @GetMapping("/page")
    public Result Page(@RequestParam @Valid Integer pageSize, @RequestParam @Valid Integer limit) {
        return Result.ok(employeesService.allEmployeesForPage(pageSize, limit));
    }
    @Operation(summary = "员工查询全部")
    @GetMapping("/all")
    public Result All() {
        return Result.ok(employeesService.allEmployees());
    }

    /**
     * 员工登录
     *
     * @param loginVo
     * @param Vcode
     * @return
     */
//    @SaIgnore
    @Operation(summary = "登录")
    @PostMapping("/verification/login/{Vcode}")
    @LogExecutionTime(message = "登录")
    @Transactional
    public Result Login(@RequestBody @Valid LoginVo loginVo, @PathVariable(value = "Vcode") @NotBlank String Vcode, HttpServletRequest request) {

        String clientIp = IpUtil.getClientIp(request);
        String key = CaptchaConstant.LOGIN_V_CODE.concat("_" + clientIp);

        if (!KeysUtil.validateCaptcha(key, Vcode)) {
            return Result.build("验证码错误 请重新输入", CAPTCHA_INVALID);
        }
        String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

        String login = employeesService.login(loginVo);
        if (!login.isBlank()) {
            if (bcrypt.matches(loginVo.getPassword(), login)) {
                Employees employees = employeesService.getByTelephone(loginVo.getTelephone());
                //切换为employees用户，进行登录
//                StpUtil.setStpLogic(employeeStpLogic);
                StpUtil.login(loginVo.getTelephone(),new SaLoginModel()
                        .setExtra("ids",employees.getEmployeeId())
                        .setExtra("email",employees.getEmail())
                        .setExtra("nickname", employees.getNickname())
                        .setExtra("role", UserRoleConstant.EMPLOYEE));

                employeesService.updateLoginStatus(clientIp, time, loginVo.getTelephone());

//                logsMapper.create(loginVo.getTelephone(), "登录");
                return Result.ok(StpUtil.getTokenInfo().tokenValue);
            } else {
                return Result.build("密码错误", PASSWORD_ERROR);
            }
        } else {
            return Result.build("用户不存在", USERNAME_ERROR);
        }
    }

    /**
     * 获取个人信息
     * @return
     */
    @Operation(summary = "个人信息")
//    @SaIgnore
    @PostMapping("/me")
    @LogExecutionTime(message = "个人信息")
    public Result Me() {
        Employees employees = employeesService.getByTelephone(StpUtil.getLoginId().toString());
        if (employees!=null) {
            return Result.ok(employees);
        } else {
            return Result.error("请先登录");
        }
    }

    /**
     * 员工更新基本信息
     *
     * @param employeeInfoVo
     * @return
     */
    @Operation(summary = "员工更新基本信息")
    @PatchMapping("/update-info/")
    @LogExecutionTime(message = "员工更新基本信息",level = LogLevel.DEBUG)
    public Result updateInfo(@RequestBody @Valid EmployeeInfoVo employeeInfoVo) {
        return Result.ok(employeesService.updateInformation(employeeInfoVo));
    }

    @PostMapping("/upload")
    @Operation(summary = "更新头像")
    @LogExecutionTime(message = "更新头像")
    public Result uploadByAliOOS(MultipartFile file) throws Exception {
        String url = aliOSSUtils.upload(file);
//        String fileName = url.substring(url.lastIndexOf('/') + 1);
//        log.info("文件上传完成, 文件名:{},文件访问的url: {}",fileName, url);
        employeesService.uploadAvatar(url,StpUtil.getLoginId().toString());
//        logsService.create("文件上传完成");
        // 将用户头像地址写入数据库 并返回给前端
        return Result.ok(url);
    }

    @GetMapping("/download")
    @Operation(summary = "用户头像")
    @SaIgnore
    public Result downloadAvatar(String telephone) throws IOException {
        String imgUrl = employeesService.getByTelephone(telephone).getImgUrl();
//        String download = aliOSSUtils.download(imgUrl);
        return Result.ok(imgUrl);
    }


    @Operation(summary = "密码更新")
    @PatchMapping("/update-password")
    @LogExecutionTime(message = "密码更新",level = LogLevel.DEBUG)
    public Result UpdatePassword(@RequestBody @Valid UpdatePasswordVo updatePasswordVo) {
        if (!Objects.equals(updatePasswordVo.getPassword(), updatePasswordVo.getRepassword())) {
            return Result.error("两次密码不一致 请重新输入");
        }
        String key = CaptchaConstant.UPDATE_V_CODE.concat("_" + updatePasswordVo.getEmail());
        System.out.println("CaptchaStorecode::" + KeysUtil.getCaptcha(key));
        if (!KeysUtil.validateCaptcha(key, updatePasswordVo.getVcode())) {
            return Result.error("验证码错误 请重新输入");
        }

        if (Objects.isNull(employeesService.getByEmail(updatePasswordVo.getEmail()))) {
            return Result.error("该用户不存在");
        } else {
            Employees employees = employeesService.getByEmail(updatePasswordVo.getEmail());
            employees.setPassword(bcrypt.encode(updatePasswordVo.getPassword()));
            try {
                if (employeesService.updateById(employees) != false) {
//                    logsService.create("更新密码成功");
                    return Result.ok("更新密码成功");
                }
//                logsService.create("更新密码失败");
                return Result.error("更新密码失败");
            } catch (SqlException e) {
                throw new SqlException("插入失败，违反唯一约束或主键冲突。");
            }
        }
    }

    /**
     * 员工登录退出
     *
     * @return
     */
    @SaCheckLogin
    @Operation(summary = "退出")
    @Transactional
    @PostMapping("/logout")
    @LogExecutionTime(message = "退出")
    public Result logout() {
//        logsService.create("退出登录");
        StpUtil.logout();
        return Result.ok("退出登录成功");
    }

    @Operation(summary = "密码重置")
    @LogExecutionTime(message = "密码重置",level = LogLevel.DEBUG)
//    @SaIgnore
    @PatchMapping("/forger-password/verification/{email}/{Vcode}")
    public Result forgerPassword(@PathVariable @NotBlank String email, @PathVariable(value = "Vcode") @NotBlank String Vcode) {
        String key = CaptchaConstant.FORGET_V_CODE.concat("_" + email);
        System.out.println("CaptchaStorecode::" + KeysUtil.getCaptcha(key));
        if (!KeysUtil.validateCaptcha(key, Vcode)) {
            return Result.error("验证码错误 请重新输入");
        }
        if (Objects.isNull(employeesService.getByEmail(email))) {
            return Result.error("该用户不存在");
        } else {
            Employees employee = employeesService.getByEmail(email);
            employee.setPassword(bcrypt.encode("123456"));
            try {
                if (employeesService.updateById(employee) != false) {
//                    logsService.create("重置密码成功");
                    return Result.ok("重置密码成功");
                }
//                logsService.create("重置密码失败");
                return Result.error("重置密码失败");
            } catch (SqlException e) {
                throw new SqlException("插入失败，违反唯一约束或主键冲突。");
            }
        }
    }


    /**
     * 查看登录会话是否登录
     *
     * @return
     */
    @Operation(summary = "员工登录会话", description = "查看登录会话是否登录")
//    @SaCheckLogin(type = UserRoleConstant.EMPLOYEE)
    @GetMapping("/is-login")
    public Result isLogin() {
        // 查看当前会话是否登录
        boolean isLogin = StpUtil.isLogin();
        String token = isLogin ? (String) StpUtil.getTokenInfo().tokenValue : null;
        return Result.build(token, isLogin ? 200 : 403, isLogin ? "员工已经登录" : "员工未登录无权操作");
    }

    /**
     * 检查是否登录
     *
     * @return
     */
    @Operation(summary = "员工是否登录", description = "员工是否登录")
//    @SaCheckLogin(type = UserRoleConstant.EMPLOYEE)
    @GetMapping("/check-login")
    public Result checkLogin() {
        // 未登录将直接报错
        StpUtil.checkLogin();
        return Result.ok("员工已经登录");
    }

}

